package org.jsola.hr.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.jsola.admin.dto.HeaderFieldsAddDTO;
import org.jsola.admin.dto.HeaderFieldsTemplateUpdateDTO;
import org.jsola.admin.dto.HeaderSortDTO;
import org.jsola.admin.query.HeaderFieldsQuery;
import org.jsola.admin.service.IHeaderFieldsService;
import org.jsola.admin.service.IHeaderFieldsTemplateService;
import org.jsola.admin.vo.HeaderFieldsListVO;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.CacheKeyKit;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IFormGroupDAO;
import org.jsola.hr.dao.IFormGroupFieldDAO;
import org.jsola.hr.dto.FormGroupAddDTO;
import org.jsola.hr.dto.FormGroupUpdateDTO;
import org.jsola.hr.entity.FormGroupDO;
import org.jsola.hr.entity.FormGroupFieldDO;
import org.jsola.hr.exception.HrException;
import org.jsola.hr.query.FormGroupQuery;
import org.jsola.hr.service.IFormGroupFieldService;
import org.jsola.hr.service.IFormGroupService;
import org.jsola.hr.vo.FormGroupListVO;
import org.jsola.hr.vo.FormGroupVO;
import org.jsola.hr.vo.FormHeaderVO;
import org.jsola.user.core.TokenUser;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 表单字段分组
 *
 * @author zhr
 */
@Slf4j
@Service("hrFormGroupServiceImpl")
public class FormGroupServiceImpl implements IFormGroupService {

    @Autowired
    private IFormGroupDAO formGroupDAO;

    @Autowired
    private IFormGroupFieldDAO formGroupFieldDAO;

    @Autowired
    private IFormGroupFieldService formGroupFieldService;

    @Autowired
    private IHeaderFieldsService headerFieldsService;

    @Autowired
    private IHeaderFieldsTemplateService headerFieldsTemplateService;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public FormGroupVO save(FormGroupAddDTO formGroupAddDTO, TokenUser tokenUser) {
        // 转DO
        FormGroupDO formGroupDO = formGroupAddDTO.to(FormGroupDO.class);
        // 保存
        formGroupDO = save(formGroupDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return formGroupDO.to(FormGroupVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<FormGroupVO> batchSave(List<FormGroupAddDTO> formGroupAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(formGroupAddDTOList)) {
            return null;
        }
        List<FormGroupDO> formGroupDOList = formGroupAddDTOList
                .parallelStream()
                .map(formGroupAddDTO -> {
                    FormGroupDO formGroupDO = formGroupAddDTO.to(FormGroupDO.class);
                    formGroupDO.preInsert(tokenUser.getUserId());
                    formGroupDO.setSiteId(tokenUser.getSiteId());
                    return formGroupDO;
                }).collect(Collectors.toList());
        formGroupDAO.insertListAndSetId(formGroupDOList);
        return formGroupDOList
                .parallelStream()
                .map(formGroupDO -> formGroupDO.to(FormGroupVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Async
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void batchSaveDO(List<FormGroupDO> insertList) {
        if (CollectionUtils.isEmpty(insertList)) {
            return;
        }
        formGroupDAO.insertListAndSetId(insertList);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(FormGroupUpdateDTO formGroupUpdateDTO, TokenUser tokenUser) {
        //转DO
        FormGroupDO formGroupDO = formGroupUpdateDTO.to(FormGroupDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(formGroupDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Boolean check, Long... formGroupIds) {
        if (!ObjectUtils.isEmpty(check) && check) {
            for (Long formGroupId : formGroupIds) {
                List<FormGroupFieldDO> formGroupFieldList = formGroupFieldService
                        .selectBySubjectIdList(Collections.singletonList(formGroupId + ""), "site");
                List<Long> fieldIdList = formGroupFieldList.stream()
                        .map(FormGroupFieldDO::getId).collect(Collectors.toList());
                Long[] fieldIdArray = new Long[fieldIdList.size()];
                formGroupFieldService.deleteByIds2(tokenUser, true, fieldIdList.toArray(fieldIdArray));
            }
        }
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) formGroupIds);
    }


    @Override
    public FormGroupVO selectById(Long formGroupId, String siteId) {
        FormGroupDO formGroupDO = selectDOById(formGroupId, siteId);
        if (formGroupDO == null) {
            return null;
        }
        return formGroupDO.to(FormGroupVO.class);
    }

    @Override
    public List<FormGroupListVO> select(FormGroupQuery formGroupQuery, String siteId) {
        List<FormGroupDO> formGroupDOList = selectDO(formGroupQuery, siteId);
        if (CollectionUtils.isEmpty(formGroupDOList)) {
            return formGroupDOList == null ? null : new ArrayList<>();
        }
        return formGroupDOList.stream()
                .map(formGroupDO -> formGroupDO.to(FormGroupListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(FormGroupQuery formGroupQuery, String siteId) {
        Example example = buildExample(formGroupQuery, siteId);
        return formGroupDAO.selectCountByExample(example);
    }

    @Override
    public Page<FormGroupListVO> selectPage(FormGroupQuery formGroupQuery, String siteId) {
        Example example = buildExample(formGroupQuery, siteId);
        Page<FormGroupDO> page = formGroupDAO.selectPageByExample(example,
                formGroupQuery.getPageNo(),
                formGroupQuery.getPageSize());

        return page.to(FormGroupListVO.class);
    }

    @Override
    public FormGroupDO selectDOById(Long formGroupId, String siteId) {
        return listById(formGroupId, siteId);
    }

    @Override
    public List<FormGroupDO> selectDO(FormGroupQuery formGroupQuery, String siteId) {
        Example example = buildExample(formGroupQuery, siteId);
        return formGroupDAO.selectByExample(example);
    }

    @Transactional
    @Override
    public List<FormGroupVO> findBySiteId(String formType, TokenUser tokenUser) {
        //查询当前租户是否有模板，如果没有复制一份系统模板到本租户
        String siteId = tokenUser.getSiteId();
        Example siteExample = new Example(FormGroupDO.class);
        siteExample.and().andEqualTo("valid", true)
                .andEqualTo("formType", "gys")
                .andEqualTo("subjectType", "site")
                .andEqualTo("subjectId", siteId);
        List<FormGroupDO> siteGroupDOList = formGroupDAO.selectByExample(siteExample);
        if (CollectionUtils.isEmpty(siteGroupDOList)) {
            Example systemExample = new Example(FormGroupDO.class);
            systemExample.and().andEqualTo("valid", true)
                    .andEqualTo("formType", "gys")
                    .andEqualTo("subjectType", "system");
            List<FormGroupDO> formGroupDOList = formGroupDAO.selectByExample(systemExample);
            formGroupDOList.stream().forEach(formGroupDO -> {
                formGroupDO.setId(null);
                formGroupDO.setSubjectType("site");
                formGroupDO.setSubjectId(siteId);
                formGroupDO.preInsert(tokenUser.getUserId());
                formGroupDO.setSiteId(tokenUser.getSiteId());
            });
            formGroupDAO.insertListAndSetId(formGroupDOList);

            List<String> moduleCodeList = formGroupDOList.stream().map(FormGroupDO::getModuleCode)
                    .collect(Collectors.toList());
            Example fieldExample = new Example(FormGroupFieldDO.class);
            fieldExample.and().andEqualTo("valid", true)
                    .andEqualTo("subjectType", "system")
                    .andIn("moduleCode", moduleCodeList);
            List<FormGroupFieldDO> fieldList = formGroupFieldDAO.selectByExample(fieldExample);
            fieldList.stream().forEach(formGroupFieldDO -> {
                formGroupFieldDO.setId(null);
                formGroupFieldDO.setSubjectType("site");
                formGroupFieldDO.setSubjectId(siteId);
                formGroupFieldDO.preInsert(tokenUser.getUserId());
                formGroupFieldDO.setSiteId(tokenUser.getSiteId());
            });
            formGroupFieldDAO.insertListAndSetId(fieldList);
        }
        List<FormGroupVO> result = formGroupDAO.findForm(siteId);
        return result;
    }

    @Override
    public FormHeaderVO getHead(HeaderFieldsQuery headerFieldsQuery, TokenUser tokenUser) {
        //module_code 和 create_user_id 作为key,防止重复操作
        String key = CacheKeyKit.getGysHeader(headerFieldsQuery.getModuleCode(), headerFieldsQuery.getCreateUserId());
        RLock lock = redissonClient.getLock(key);
        boolean hasLock;
        try {
            // 加锁，等待0秒，上锁以后2分钟自动解锁
            hasLock = lock.tryLock(0, 2, TimeUnit.MINUTES);
            if (!hasLock) {
                int count = 0;
                while (count < 3) {
                    Thread.sleep(1000);
                    count++;
                }
                throw new HrException("正在查询表头，稍后重试");
            }
        } catch (InterruptedException e) {
            log.error("查询表头异常：", e);
            throw new RuntimeException(e);
        }

        //系统默认设置的
        HeaderSortDTO headerSortDTO = headerFieldsTemplateService.selectAll(headerFieldsQuery.getModuleCode(), tokenUser);
        if (headerSortDTO == null) {
            throw new ParamException("不存在" + headerFieldsQuery.getModuleCode() + "类别的系统表头设置");
        }
        List<HeaderFieldsTemplateUpdateDTO> systemCansee = headerSortDTO.getCanSeeList();
        List<HeaderFieldsTemplateUpdateDTO> systemIgnore = headerSortDTO.getNotSeeList();
        List<HeaderFieldsTemplateUpdateDTO> systemField = new ArrayList<>();
        if (systemCansee != null) {
            systemField.addAll(systemCansee);
        }
        if (systemIgnore != null) {
            systemField.addAll(systemIgnore);
        }

        //用户自定义表头
        List<HeaderFieldsListVO> select = headerFieldsService.select(headerFieldsQuery, tokenUser.getSiteId());

        List<HeaderFieldsListVO> canSee = new ArrayList<>();
        List<HeaderFieldsListVO> ignore = new ArrayList<>();
        List<HeaderFieldsListVO> addition = new ArrayList<>();
        List<HeaderFieldsListVO> additionAll = new ArrayList<>();

        //如果用户没有自定义过，就查询系统的，然后保存一份
        if (CollectionUtils.isEmpty(select)) {
            List<HeaderFieldsAddDTO> param = new ArrayList<>();
            for (HeaderFieldsTemplateUpdateDTO headerFieldsTemplateUpdateDTO : systemField) {
                HeaderFieldsAddDTO headerField = new HeaderFieldsAddDTO();
                headerField.setFieldEnName(headerFieldsTemplateUpdateDTO.getCode());
                headerField.setFieldName(headerFieldsTemplateUpdateDTO.getName());
                headerField.setModuleCode(headerFieldsTemplateUpdateDTO.getModuleCode());
                headerField.setModuleType(headerFieldsTemplateUpdateDTO.getModuleType());
//                headerField.setIsFix();
                headerField.setIsEdit(headerFieldsTemplateUpdateDTO.getIsEdit());
                headerField.setIsOpen(headerFieldsTemplateUpdateDTO.getIsSee());
                headerField.setSort(headerFieldsTemplateUpdateDTO.getSort());
                headerField.setSubjectId(tokenUser.getSiteId());
                headerField.setSubjectType("site");
                param.add(headerField);
            }

            headerFieldsService.batchSave(param, tokenUser);
            select = headerFieldsService.select(headerFieldsQuery, tokenUser.getSiteId());
        }

        lock.unlock();

        for (HeaderFieldsListVO headerFieldsListVO : select) {
            if (headerFieldsListVO.getIsOpen()) {
                canSee.add(headerFieldsListVO);
            } else {
                ignore.add(headerFieldsListVO);
            }
        }

        List<String> canSeeEnName = canSee.stream().map(HeaderFieldsListVO::getFieldEnName)
                .collect(Collectors.toList());

        //租户定义的所有字段（系统 + 自定义的）
        FormGroupFieldDO formGroupFieldDO = new FormGroupFieldDO();

        List<FormGroupFieldDO> fieldListVOS = formGroupFieldService.list(formGroupFieldDO, tokenUser.getSiteId());
        for (FormGroupFieldDO fieldListVO : fieldListVOS) {
            //1 是 系统字段；2是自定义字段
            Integer source = fieldListVO.getFieldSource();
            // 排除字段类型是7的，文件类型
            Integer fieldType = fieldListVO.getFieldType();
            String fieldId = String.valueOf(fieldListVO.getId());
            if (source == 2 && fieldType != 7) {
                HeaderFieldsListVO headerFieldsListVO = new HeaderFieldsListVO();
                headerFieldsListVO.setFieldName(fieldListVO.getFieldName());
                headerFieldsListVO.setFieldEnName(fieldId);
                headerFieldsListVO.setIsEdit(true);
                headerFieldsListVO.setIsFix(false);
                headerFieldsListVO.setIsOpen(true);
                additionAll.add(headerFieldsListVO);
                if (!canSeeEnName.contains(fieldId)) {
                    //可选自定义字段 = 系统全部自定义字段 - 已选中的自定义字段
                    addition.add(headerFieldsListVO);
                }
            }
        }

        FormHeaderVO formHeaderVO = new FormHeaderVO();
        //已选表头（系统 + 自定义）
        formHeaderVO.setCanSee(canSee);
        //未选的系统表头
        formHeaderVO.setIgnore(ignore);
        //未选的自定义表头
        formHeaderVO.setAddition(addition);
        //所有的自定义表头
        formHeaderVO.setAdditionAll(additionAll);
        return formHeaderVO;
    }

    @Override
    public List<FormGroupDO> selectDefaultFormByType(String formType) {
        Example example = new Example(FormGroupDO.class);
        example.and()
                .andEqualTo("formType", formType)
                .andEqualTo("subjectType", "system");
        return formGroupDAO.selectByExample(example);
    }

    @Override
    public List<FormGroupVO> selectBySubjectIdAndFormType(String subjectId, String formType,
                                                          String moduleCode, TokenUser tokenUser) {
        Example example = new Example(FormGroupDO.class);
        example.and()
                .andEqualTo("formType", formType)
                .andEqualTo("valid", true)
                .andEqualTo("subjectId", subjectId);
        if(!StringUtils.isEmpty(moduleCode)){
            example.and().andEqualTo("moduleCode", moduleCode);
        }
        example.orderBy("level").orderBy("sort");
        List<FormGroupDO> formGroupList = formGroupDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(formGroupList)) {
            return new ArrayList<>();
        } else {
            return formGroupList.stream()
                    .map(formGroup -> formGroup.to(FormGroupVO.class))
                    .collect(Collectors.toList());
        }
    }

    @Override
    public List<FormGroupVO> buildFormGroupTree(List<FormGroupVO> formGroupList) {
        return null;
    }

    /**
     * 根据查询参数，构建example
     *
     * @param formGroupQuery 查询参数
     * @param siteId         所属站点id
     * @return example
     */
    private Example buildExample(FormGroupQuery formGroupQuery, String siteId) {
        Example example = new Example(FormGroupDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (formGroupQuery.getParentId() != null) {
            example.and().andEqualTo("parentId", formGroupQuery.getParentId());
        }
        if (formGroupQuery.getLevel() != null) {
            example.and().andEqualTo("level", formGroupQuery.getLevel());
        }
        // 排序
        ExampleKit.setExampleOrder(example, formGroupQuery.getOrders());
        return example;
    }
}





